using System;
using System.Threading;
using Gj.Galaxy.Logic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Gj.MapData
{
    public class StandardExecutor
    {
        protected string _content;
        protected string _mapNoId;

        public string Content => _content;

        public string CurrentMapNoId
        {
            get => !string.IsNullOrEmpty(_mapNoId) ? _mapNoId : CooperateConnect.MapNoId;
            set => _mapNoId = value;
        }

        public object NodeId(Vector2Int position)
        {
            return SerializeInt.Vector2Byte(position);
        }

        public object NodeIds(Vector2Int[] positions)
        {
            return SerializeInt.Vector2Byte(positions);
        }

        public CheckBuilder CheckBuilder()
        {
            return MapData.CheckBuilder.Get();
        }

        public CheckBuilder C()
        {
            return MapData.CheckBuilder.Get();
        }

        public OperateBuilder OperateBuilder()
        {
            return MapData.OperateBuilder.Get(this);
        }

        public OperateBuilder O()
        {
            return MapData.OperateBuilder.Get(this);
        }

        public ScheduleBuilder ScheduleBuilder()
        {
            return MapData.ScheduleBuilder.Get(this);
        }

        public ScheduleBuilder S()
        {
            return MapData.ScheduleBuilder.Get(this);
        }

        public TaskBuilder TaskBuilder()
        {
            return MapData.TaskBuilder.Get(this);
        }

        public TaskBuilder T()
        {
            return MapData.TaskBuilder.Get(this);
        }

        public EventBuilder EventBuilder()
        {
            return MapData.EventBuilder.Get(this);
        }

        public EventBuilder E()
        {
            return MapData.EventBuilder.Get(this);
        }

        public virtual long Delay(float delaySecond)
        {
            return (long)(delaySecond * 1000);
            // return TimeTools.FormatTime(delaySecond);
        }

        public virtual int DelaySecond(float delaySecond)
        {
            return TimeTools.FormatSecond(delaySecond);
        }

        public virtual void Operate(OperateBuilder builder, CheckBuilder check, long delay)
        {
            CooperateConnect.Operate(builder.MapNoId, builder._from.Object(), builder._target.Object(), CheckData.TwoArray(check?.Data()), OperateData.Array(builder._all.ToArray()), delay, builder._operateMessage.Object());
        }

        public virtual void Schedule(ScheduleBuilder builder)
        {
            CooperateConnect.AddSchedule(builder._mapNoId, builder._from.Object(), builder._target.Object(), builder._key, (byte)builder._logic, builder._time, builder._schedule.Object(), builder._param, builder._delay);
        }

        public virtual void Task(string mapNoId, object from, byte task, long time, object content, object[] param, string uuid)
        {
            CooperateConnect.AddTask(mapNoId, from, task, time, content, param, uuid);
        }

        // public void BindEvent(string mapNoId, object from, object target, byte Event, EventMode mode, object content)
        // {
        //     CooperateConnect.BindEvent(mapNoId, from, target, Event, (byte)mode, content);
        // }
    }

    public interface TaskBlock
    {
        void Process(Action<bool> finish);
    }

    public interface TaskFlow
    {
        void Pre();
        bool Gap(int gapTime);
        void OnStop();
    }

    public class TaskContainer
    {
        private static bool GlobalStop = true;
        private TaskFlow _instance;

        private Thread _thread;
        private bool canNext;
        private int currentDelay;

        private int delay;

        public int Gap = 100;
        private bool isRun;
        private readonly int maxDelay = 1000;
        private readonly int minDelay = 100;
        private int queue;
        public int target;

        static TaskContainer()
        {
#if UNITY_EDITOR
            EditorApplication.playModeStateChanged += DispatchEdit;
#endif
        }

#if UNITY_EDITOR
        private static void DispatchEdit(PlayModeStateChange state)
        {
            switch (state)
            {
                case PlayModeStateChange.EnteredEditMode:
                    GlobalStop = true;
                    break;
                case PlayModeStateChange.EnteredPlayMode:
                    GlobalStop = false;
                    break;
            }
        }

#endif
        public void Dispatch(TaskFlow instance)
        {
            Debug.LogError("[ Executor ] Task Dispatch:"+isRun);
            if (isRun) return;
            _instance = instance;
            isRun = true;
            GlobalStop = false;
            canNext = true;
            ThreadStart threadStart = () =>
            {
                // var startTime = TimeTools.CurrentMill();
                try
                {
                    while (isRun)
                    {
                        if (GlobalStop)
                        {
                            instance.OnStop();
                            break;
                        }

                        var current = 1;
                        current += Gap;
                        delay += current;
                        // 根据queue数量和target，决定查询间隔
                        // target为0，不缩短查询间隔
                        // queue大于0，增加查询间隔

                        if (canNext || instance.Gap(delay))
                            if (delay >= currentDelay)
                            {
                                // 重新矫正delay:
                                // 提早完成，缩短delay时间
                                if (target > 0 && queue == 0)
                                {
                                    currentDelay -= Gap;
                                    if (currentDelay <= minDelay) currentDelay = minDelay;
                                }
                                // 还未完成，延长delay时间
                                else if (target > 0 && queue > 0)
                                {
                                    currentDelay += Gap;
                                    if (currentDelay >= maxDelay) currentDelay = maxDelay;
                                }
                                else
                                {
                                    // 没有数据，缓慢调整到基础状态
                                    if (currentDelay < (maxDelay - minDelay) / 2)
                                        currentDelay += Gap;
                                    else
                                        currentDelay -= Gap;
                                }

                                // Debug.LogError("[ Executor ] Task delay:" + delay + ":" + currentDelay+"->"+queue+":"+target);
                                canNext = false;
                                target = 0;
                                instance.Pre();
                                delay = current;
                            }

                        Thread.Sleep(current);
                    }
                }
                catch (Exception e)
                {
                    Debug.LogException(e);
                }

                _thread = null;
            };
            // 创建多线程对象
            _thread = new Thread(threadStart);
            // 运行多线程
            _thread.Start();
        }

        public void OnDone()
        {
            canNext = true;
        }

        public void PreResult(TaskBlock task)
        {
            // var startTime = TimeTools.CurrentMill();
            // Debug.LogError("queue:"+queue);
            Interlocked.Increment(ref target);
            Interlocked.Increment(ref queue);
            ThreadPool.QueueUserWorkItem(s =>
            {
                task.Process(result =>
                {
                    Interlocked.Decrement(ref queue);
                    // Debug.LogError("queue time:"+(TimeTools.CurrentMill()-startTime));
                });
            });
        }

        public void Abort()
        {
            if (_thread != null)
            {
                _thread.Abort();
                Debug.LogError("[ Executor ] Task Abort");

                _thread = null;
                isRun = false;
            }
        }

        public void Stop()
        {
            isRun = false;
            Abort();
        }
    }
}